/*
  (C) 2007 - Boston University
  Contact: Michael Ocean 

	this file was adapted from a CS511 submission

  This work is a part of the larger snBench project.  Information
  can be found at: http://csr.bu.edu/snbench 

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package stepide;

import stepide.STEPVisualizer.JStepPanel;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.io.File;

import javax.imageio.ImageIO;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JFileChooser;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import step.Node;
import step.TriggerReadNode;
import stepide.opcodes.Opcode;
import stepide.opcodes.OpcodeLibrary;


/**
 * Overview: This class constructs the floating palette for selecting/adding a node to
 * a STEP graph. 
 * 
 * Users can select nodes that are opcodes, constants, or STEP constructs.
 * 
 */
public class NodeSelector extends javax.swing.JDialog implements Serializable {
	private JButton btnClose;
	private JTabbedPane jtp;
	private JPanel opcodePanel;
	private JButton btnOpcode;
	private JButton btnConstruct;
	private JButton btnConstant;
	private JButton btnClear;
	private JPanel constructsPanel;
	private JPanel constantsPanel;
	private final JTextField txtConstStr = new JTextField(5);
	private final JTextField txtConstInt = new JTextField(5);
	private final JTextField txtConstDbl = new JTextField(5);
	private final JTextField txtConstLong = new JTextField(5);
	private final JTextField txtConstImage = new JTextField(10);
	private JComboBox comboTriggerId = new JComboBox();
	private JComboBox comboSpliceTarget = new JComboBox();
	private JComboBox comboReadMode = new JComboBox(new String[] { "Fresh", "Blocking", "Non-Blocking" } );
	private final JComboBox comboConstBool = new JComboBox(new String[] {"", "true", "false"});	

	private String[] constructData = { "cond", "trigger", "edge_trigger", "level_trigger", "last_trigger_eval", "flowtype", "read", "const", "splice", "socket" };
	private String[] constTypes = { "Boolean", "Long", "Double", "Integer", "String", "Image" };
	private JComboBox constructList = new JComboBox(constructData);
	
	private FilteredOpcodeList opcodeFloat;
	private NodeSelector me = null;
	private Opcode _userSelectionOpcode = null;
	private String _userSelectionString = null;
	private Double _userSelectionDouble = null;
	private Integer _userSelectionInteger = null;
	private Long _userSelectionLong = null;
	private Boolean _userSelectionBoolean = null;
	private BufferedImage _userSelectionImage = null;
	private String _userSelectionImagePath = null;
	private String _userSelectionSN = null;
	
	private step.Node _userSelectionOther = null;
	private static int _mostRecentNodeId = 0; //IDs shared across all graphs so must be static
		
	
	private JStepPanel _stepGraph = null;
	private JEditorPane opcodeDesc;
	private static final long serialVersionUID = 20070427L;

	/**
	 * Creates a view component containing the specified text.
	 * 
	 * @param text
	 *            the text
	 * @return the view component
	 */
	private JComponent createViewComponent() {
		opcodeDesc = new JEditorPane("text/html","");
		opcodeDesc.setEditable(false);
				
		//opcodeDesc.setWrapStyleWord(true);
		//opcodeDesc.setLineWrap(true);
		return new JScrollPane(opcodeDesc);
	}
	
	public NodeSelector(JStepPanel stepGraph) 
	{
		super();
		this.setLocationRelativeTo(null); // forces center
		this.setModal(true);
		_stepGraph = stepGraph;	
		opcodeFloat = new FilteredOpcodeList(OpcodeLibrary.getLibrary().getOpcodeNameList());
		opcodeFloat.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				resetUserSelection();
				_userSelectionOpcode = OpcodeLibrary.getLibrary().get((String) opcodeFloat.getSelectedValue());
				
				opcodeFloat.setToolTipText(_userSelectionOpcode.toString());
				
				opcodeDesc.setText(_userSelectionOpcode.toString());
				
			}
		});
		
		me = this;

		initGUI();
	}

	private void initGUI() {
		try {
			BorderLayout thisLayout = new BorderLayout();
			getContentPane().setLayout(thisLayout);
			this.setTitle("Node Selector");

			JPanel panelButton = new JPanel(new BorderLayout());
			
			btnClose = new JButton("Close");
			panelButton.add(btnClose, BorderLayout.EAST);
			btnClose.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e)
				{
						resetUserSelection();
						me.setVisible(false);
				}
			});
			
			btnClear = new JButton("Clear Selections");
			panelButton.add(btnClear, BorderLayout.WEST);
			btnClear.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					resetUserSelection();
				}
			});

			getContentPane().add(panelButton, BorderLayout.SOUTH);
			
			jtp = new JTabbedPane();
			getContentPane().add(jtp, BorderLayout.CENTER);
			
			createOpcodesTab();
			createConstantsTab();
			createConstructsTab();

			/*
			DefaultGraphCell scell = (DefaultGraphCell) _selectedParent;	
			if(scell.getUserObject() instanceof stepgraph.Node)
			{
				stepgraph. n = (stepgraph.Node) scell.getUserObject();
				step.Node parentNode = n.getStepNode();
				
				if(parentNode instanceof step.ValueNode)
				{
					disableOpcodesTab();
					disableConstantsTab();
					disableConstructsTab();
				}
				else if(parentNode instanceof step.LastTriggerEval)
				{
					
				}			
			}	
			*/
			this.setSize(575, 450);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void createOpcodesTab() {
		opcodePanel = new JPanel(new BorderLayout());
		JScrollPane jsp = new JScrollPane(opcodeFloat, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
	
		btnOpcode = new JButton();
		btnOpcode.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (_userSelectionOpcode == null) {
					JOptionPane.showMessageDialog(null, "Please choose an opcode.");
				}
				else me.close();
			}
		});
		
		JSplitPane jsplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		jsplit.setLeftComponent(jsp);
		jsplit.setDividerSize(3);
		
		jsplit.setRightComponent(createViewComponent());
		
		opcodePanel.add(jsplit, BorderLayout.CENTER);
		
		
		opcodePanel.add(opcodeFloat.getFilterField(), BorderLayout.NORTH);
		opcodePanel.add(btnOpcode, BorderLayout.SOUTH);
		btnOpcode.setText("Add Opcode");
		
		jtp.addTab("Opcodes", null, opcodePanel, null);
	}

	private void createConstantsTab() {
		JPanel backer = new JPanel(new BorderLayout());
		
		JPanel comboBoxPane = new JPanel(); //use FlowLayout
		JComboBox constSelect = new JComboBox(constTypes);
		JLabel lbl = new JLabel("Constant Type:");
		constSelect.setEditable(false);
		constSelect.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent evt) {
		        CardLayout cl = (CardLayout)(constantsPanel.getLayout());
		        cl.show(constantsPanel, (String)evt.getItem());
		    }
		});
		
		comboBoxPane.add(lbl);
		comboBoxPane.add(constSelect);
		
		// create the cards
		JPanel bool = new JPanel();
		bool.add(new JLabel("Value:"));
		bool.add(comboConstBool);
		
		JPanel integer = new JPanel();
		integer.add(new JLabel("Value:"));
		integer.add(txtConstInt);
		
		JPanel doubleC = new JPanel();
		doubleC.add(new JLabel("Value:"));
		doubleC.add(txtConstDbl);
		
		JPanel longC = new JPanel();
		longC.add(new JLabel("Value:"));
		longC.add(txtConstLong);

		JPanel string = new JPanel();
		string.add(new JLabel("Value:"));
		string.add(txtConstStr);

		JPanel image = new JPanel();
		image.add(new JLabel("File path:"));
		image.add(txtConstImage);
		JButton findImageButton = new JButton("Browse...");
		findImageButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				JFileChooser open = new JFileChooser();
				int returnVal = open.showOpenDialog(me);
				if (returnVal == JFileChooser.APPROVE_OPTION) 
				{
					txtConstImage.setText(open.getSelectedFile().getPath());
				}
			}
		});
		image.add(findImageButton);
		
		constantsPanel = new JPanel(new CardLayout());
		constantsPanel.add(bool, "Boolean");
		constantsPanel.add(longC, "Long");
		constantsPanel.add(doubleC, "Double");
		constantsPanel.add(integer, "Integer");
		constantsPanel.add(string, "String");
		constantsPanel.add(image, "Image");
		
		backer.add(comboBoxPane, BorderLayout.PAGE_START);
		backer.add(constantsPanel, BorderLayout.CENTER);
		
		btnConstant = new JButton("Add Constant");
		btnConstant.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doActionBtnConstant(e);
			}
		});
		
		backer.add(btnConstant, BorderLayout.SOUTH);
		jtp.addTab("Constants", null, backer, null);
	}

	private void createConstructsTab() {
		JPanel backer = new JPanel(new BorderLayout());
		
		JPanel comboBoxPane = new JPanel(); //use FlowLayout
		JLabel lbl = new JLabel("Construct type:");
		constructList.setEditable(false);
		constructList.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent evt) {
		        CardLayout cl = (CardLayout)(constructsPanel.getLayout());
		        cl.show(constructsPanel, (String)evt.getItem());
		    }
		});
		
		comboBoxPane.add(lbl);
		comboBoxPane.add(constructList);
		
		// Making JPanels for every construct type so that it's easy to add
		// value fields in the future should we need it
		JPanel read = new JPanel();
		read.add(new JLabel("Value:"));
		read.add(comboReadMode);
		
		JPanel splice = new JPanel();
		splice.add(new JLabel("Splice Target: "));
		splice.add(comboSpliceTarget);
		
		JPanel lastTriggerEval = new JPanel();
		lastTriggerEval.add(new JLabel("Trigger ID: "));
		lastTriggerEval.add(comboTriggerId);
		
		JPanel trigger = new JPanel();
		JPanel edgeTrigger = new JPanel();
		JPanel levelTrigger = new JPanel();
		JPanel cond = new JPanel();
		JPanel flowType = new JPanel();
		JPanel constC = new JPanel();
		JPanel socket = new JPanel();
		
		constructsPanel = new JPanel(new CardLayout());
		constructsPanel.add(cond, "cond"); //add this first so it is visible and matches up to combobox
		constructsPanel.add(read, "read");
		constructsPanel.add(splice, "splice");
		constructsPanel.add(trigger, "trigger");
		constructsPanel.add(edgeTrigger, "edge_trigger");
		constructsPanel.add(levelTrigger, "level_trigger");
		constructsPanel.add(lastTriggerEval, "last_trigger_eval");
		constructsPanel.add(flowType, "flowtype");
		constructsPanel.add(constC, "const");
		constructsPanel.add(socket, "socket");
		
		backer.add(comboBoxPane, BorderLayout.NORTH);
		backer.add(constructsPanel, BorderLayout.CENTER);
		
		btnConstruct = new JButton("Add STEP Construct");
		btnConstruct.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doActionBtnConstruct(e);
			}
		});
		
		backer.add(btnConstruct, BorderLayout.SOUTH);
		jtp.addTab("Constructs", null, backer, null);
	}

	private void doActionBtnConstant(ActionEvent evt) {
		if (txtConstStr.getText().length() > 0) {
			resetUserSelection();
			_userSelectionString = txtConstStr.getText();
			_userSelectionSN = "snString";
			me.close();
		}
		else if (txtConstInt.getText().length() > 0) {
			try {
				resetUserSelection();
				_userSelectionInteger = Integer.parseInt(txtConstInt.getText());
				_userSelectionSN = "snInteger";
				me.close();
			}
			catch (java.lang.NumberFormatException ex) {
				JOptionPane.showMessageDialog(me, "Please enter a valid integer value.");
			}
		}
		else if (txtConstDbl.getText().length() > 0) {
			try {
				resetUserSelection();
				_userSelectionDouble = Double.parseDouble(txtConstDbl.getText());
				_userSelectionSN = "snDouble";
				me.close();
			}
			catch (java.lang.NumberFormatException ex) {
				JOptionPane.showMessageDialog(me, "Please enter a valid double value.");
			}
		}	
		else if(txtConstLong.getText().length() > 0)
		{
			try
			{
				resetUserSelection();
				_userSelectionLong = Long.parseLong(txtConstLong.getText());
				_userSelectionSN = "snLong";
				me.close();
			}
			catch(java.lang.NumberFormatException ex)
			{
				JOptionPane.showMessageDialog(me, "Please enter a valid long value.");
			}
		}
		else if (txtConstImage.getText().length() > 0)
		{
			try
			{
				resetUserSelection();
				File f = new File(txtConstImage.getText());
   				_userSelectionImage = ImageIO.read(f);
				_userSelectionImagePath = txtConstImage.getText();
				_userSelectionSN = "snImage";
				me.close();
			}
			catch(java.io.IOException ex)
			{
				JOptionPane.showMessageDialog(me, "Please enter a valid image path.");
			}

		}
		else if (comboConstBool.getSelectedItem().toString().length() > 0) {
			if (comboConstBool.getSelectedItem().toString().equalsIgnoreCase("true") || comboConstBool.getSelectedItem().toString().equalsIgnoreCase("false")) {
				resetUserSelection();
				_userSelectionBoolean = Boolean.parseBoolean(comboConstBool.getSelectedItem().toString());
				_userSelectionSN = "snBoolean";
				me.close();
			}
			else {
				JOptionPane.showMessageDialog(me, "Please select a valid boolean value from the list.");
			}
		}
		

		txtConstStr.setText("");
		txtConstInt.setText("");
		txtConstDbl.setText("");
		txtConstLong.setText("");
		txtConstImage.setText("");
		comboConstBool.setSelectedItem((String) "");
	}
	
	private void doActionBtnConstruct(ActionEvent evt) {
			String constructName = (String) constructList.getSelectedItem();
			step.Node stepNode = null;
			if (constructName.equalsIgnoreCase("cond")) {
				stepNode = new step.ConditionalNode(getNewNodeId(constructName));
			}
			else if (constructName.equalsIgnoreCase("trigger")) {
				stepNode = new step.TriggerNode(getNewNodeId(constructName));
			}
			else if (constructName.equalsIgnoreCase("edge_trigger")) {
				stepNode = new step.EdgeTriggerNode(getNewNodeId(constructName));
			}
			else if (constructName.equalsIgnoreCase("level_trigger")) {
				stepNode = new step.LevelTriggerNode(getNewNodeId(constructName));
			}
			else if (constructName.equalsIgnoreCase("last_trigger_eval")) {
				stepNode = new step.LastTriggerEval(getNewNodeId(constructName), comboTriggerId.getSelectedItem().toString());
			}
			else if (constructName.equalsIgnoreCase("read")) 
			{
				stepNode = new step.TriggerReadNode(getNewNodeId(constructName), getReadMode());
			}
			else if (constructName.equalsIgnoreCase("const")) {
				stepNode = new step.ConstNode(getNewNodeId(constructName));
			}
			else if (constructName.equalsIgnoreCase("splice")) {
				stepNode = new step.SpliceNode(getNewNodeId(constructName), comboSpliceTarget.getSelectedItem().toString());
			}
			else if (constructName.equalsIgnoreCase("socket")) {
				throw new RuntimeException("socket not currently implemented");
			}

			resetUserSelection();
			_userSelectionOther = stepNode;

		if (_userSelectionOther == null) {
			JOptionPane.showMessageDialog(null, "Please choose a node type to add.");
		}
		else {
			me.close();
		}
	}

	private void close()
	{
		this.setVisible(false);

		/*
		String error = validateSelection();
		if(error.length() == 0)
		{
			this.setVisible(false);
		}
		else {
			JOptionPane.showMessageDialog(null, "Your selection is invalid for that node type.\n" +
					"You may have chosen an incorrect input type, \nthe node already has the maximum number of\n" + 
					"allowed inputs," + "or possibly due to: " + error + ". \n\nConsult the opcode documentation to determine \n" +
					"which nodes allow which inputs and then \nplease try again.");
			resetUserSelection();
		}
		*/
	}

	/**
	private String validateSelection()
	{
		String error = new String("some other reason.");
		DefaultGraphCell scell = (DefaultGraphCell) _selectedParent;	
		step.Node parentNode = null;
		if(scell.getUserObject() instanceof stepgraph.Node)
		{
			 parentNode = (stepgraph.Node) scell.getUserObject();
		}	
		else
		{
			return new String(); //1st node is always allowed ("stepgraph" node user object is a string not a stepgraph.Node)
		}
		
		int childPosition = parentNode.getStepNode().getChildren().length;	
		int existingChildCount = childPosition + 1;	
		if(parentNode.getStepNode() instanceof step.ValueNode)
		{
			return "Value nodes do not allow children"; 
		}
		else if (parentNode.getStepNode() instanceof step.ConditionalNode)
		{
			if(existingChildCount == 3)
			{
				return "The maximum number of children for a conditional node is 3 and has already been reached.";
			}
		}
		else if (parentNode.getStepNode() instanceof step.LastTriggerEval)
		{
			return "Last Trigger Eval nodes cannot have children.";
		}
		else if (parentNode.getStepNode() instanceof step.ConstNode)
		{
			if(existingChildCount == 1)
			{
				return "Const nodes cannot have more than 1 child";
			}
		}
		
		Opcode opcode = OpcodeLibrary.getLibrary().get(parentNode.toString());
		if(opcode != null)
		{
			TypeSignature[] types = opcode.getTypeSignatures();
			for(int i = 0; i < types.length; i++)
			{
				String[] inputTypes = (String[]) types[i].getInputTypes().toArray(new String[0]);
				if(!(childPosition < inputTypes.length))
				{
					error = "The maximum number of children has been reached for that opcode";
					break;
				}
								
				if(inputTypes[childPosition].equalsIgnoreCase(getUserSelectionSN()))
				{
					error = new String();
					break;
				}
			}	

		}
		else
		{
			error = new String(); //only validate opcodes for the moment...
		}

		return error;
	}
	**/
	
	private void updateSpliceTargetComboBox()
	{
		comboSpliceTarget.removeAllItems();
		String[] targets = _stepGraph.getPossibleSpliceTargets();
		for(int i = 0; i < targets.length; i++)	
		{
			comboSpliceTarget.addItem(targets[i]);
		}
	}
	
	private void updateTriggerIdComboBox()
	{
		comboTriggerId.removeAllItems();
		String[] triggerIds = _stepGraph.getPossibleLTETriggerIds();
		for(int i = 0; i < triggerIds.length; i++)
		{
			comboTriggerId.addItem(triggerIds[i]);
		}
		
	}

	private void disableOpcodesTab()
	{
		jtp.setEnabledAt(0, false);
	}
	
	private void disableConstantsTab()
	{
		jtp.setEnabledAt(1, false);
	}				

	private void disableConstructsTab()
	{
		jtp.setEnabledAt(2, false);
	}					

	private String getNewNodeId(String prefix) 
	{	
		return _stepGraph.requestNextNodeID(prefix);		
	}
	
	private boolean userSelectedInteger() {
		return _userSelectionInteger != null;
	}

	private boolean userSelectedDouble() {
		return _userSelectionDouble != null;
	}

	private boolean userSelectedLong()
	{
		return _userSelectionLong != null;
	}

	private boolean userSelectedOpcode() {
		return _userSelectionOpcode != null;
	}

	private boolean userSelectedString() {
		return _userSelectionString != null;
	}

	private boolean userSelectedOther() {
		return _userSelectionOther != null;
	}

	private boolean userSelectedBoolean() {
		return _userSelectionBoolean != null;
	}

	private boolean userSelectedImage()
	{
		return _userSelectionImage != null;
	}

	private int getUserSelectionInteger() {
		return _userSelectionInteger.intValue();
	}

	private double getUserSelectionDouble() {
		return _userSelectionDouble.doubleValue();
	}

	private long getUserSelectionLong()
	{
		return _userSelectionLong.longValue();
	}

	private String getUserSelectionString() {
		return _userSelectionString;
	}

	private boolean getUserSelectionBoolean() {
		return _userSelectionBoolean.booleanValue();
	}

	private BufferedImage getUserSelectionImage()
	{
		return _userSelectionImage;
	}

	private String getUserSelectionImagePath()
	{
		return _userSelectionImagePath;
	}

	private Opcode getUserSelectionOpcode() {
		return _userSelectionOpcode;
	}

	private step.Node getUserSelectionOther() {
		return _userSelectionOther;
	}
	
	private String getUserSelectionSN()
	{
		return _userSelectionSN;
	}
	
	private TriggerReadNode.ReadMode getReadMode()
	{
		String readMode = (String) comboReadMode.getSelectedItem();
		if(readMode.equalsIgnoreCase("non-blocking"))
		{
			return TriggerReadNode.ReadMode.NONBLOCK;
		}
		else if(readMode.equalsIgnoreCase("blocking"))
		{
			return TriggerReadNode.ReadMode.BLOCK;
		}
		else if(readMode.equalsIgnoreCase("NEXT"))
		{
			return TriggerReadNode.ReadMode.NEXT;
		}	
		
		return null;
	}

	/**
		Effects: resets the current user selection to no selection
	*/
	public void resetUserSelection() 
	{
		_userSelectionOpcode = null;
		_userSelectionString = null;
		_userSelectionDouble = null;
		_userSelectionInteger = null;
		_userSelectionBoolean = null;
		_userSelectionImage = null;
		_userSelectionImagePath = null;
		_userSelectionLong = null;
		_userSelectionOther = null;
		_userSelectionSN = null;
	}

	/**
		Effects: Updates splice targets and possible Last Trigger Eval targest with any newly added nodes
	*/
	public void updateAvailableItems(JStepPanel currentPanel)
	{
		_stepGraph = currentPanel;
		if(_stepGraph != null)
		{
			updateSpliceTargetComboBox();
			updateTriggerIdComboBox();	
		}
	}
	
	/**
		Effects: Returns the user selected node 
	*/
	public Node getUserSelectedNode() {
		step.Node stepNode = null;
		String name = null;
		String nodeId ;
		
		if (userSelectedOpcode()) {
			name = getUserSelectionOpcode().getFqn();
			nodeId = getNewNodeId(name.substring(name.lastIndexOf(".")+1));
			stepNode = new step.ExpNode(nodeId, name);
		}
		else if (userSelectedInteger()) {
			int i = getUserSelectionInteger();
			name = ((Integer) i).toString();
			nodeId = getNewNodeId("int" + name);
			stepNode = new step.ValueNode(nodeId, new snobject.snInteger(i));
		}
		else if (userSelectedDouble()) {
			double d = getUserSelectionDouble();
			name = ((Double) d).toString();
			nodeId = getNewNodeId("double" + name);
			stepNode = new step.ValueNode(nodeId, new snobject.snDouble(d));
		}
		else if (userSelectedString()) {
			String s = getUserSelectionString();
			name = s;
			nodeId = getNewNodeId("string");
			stepNode = new step.ValueNode(nodeId, new snobject.snString(s));
		}
		else if (userSelectedLong())
		{
			Long l = getUserSelectionLong();
			name = ((Long)l).toString();
			nodeId = getNewNodeId("long" + name);
			stepNode = new step.ValueNode(nodeId, new snobject.snLong(l));
		}
		else if (userSelectedBoolean()) {
			boolean b = getUserSelectionBoolean();
			name = ((Boolean) b).toString();
			nodeId = getNewNodeId("bool" + name);
			stepNode = new step.ValueNode(nodeId, new snobject.snBoolean(b));
		}
		else if (userSelectedImage())
		{
			BufferedImage image = getUserSelectionImage();
			name = getUserSelectionImagePath();
			nodeId = getNewNodeId("img" + name);
			stepNode = new step.ValueNode(nodeId, new snobject.snImage(image));
		}
		else if (userSelectedOther()) 
		{
			stepNode = getUserSelectionOther();
			name = stepNode.toString();
		}

		return stepNode;
	}
}